package com.parse.antlr.tree.parsers.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

import com.commons.ParsingResult;
import com.parse.antlr.tree.parsers.ANTLRv3Lexer;
import com.parse.antlr.tree.parsers.ANTLRv3Parser;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class CustomParser implements Callable<ParsingResult> {

	private  List<org.antlr.runtime.tree.Tree> variableDeclartorNodes = new ArrayList<org.antlr.runtime.tree.Tree>();
	private  List<String> variableList = new ArrayList<String>();
	private  List<String> keywordList = new ArrayList<String>();
	private  List<String> stringNodes = new ArrayList<String>();
	private  List<String> strcharNodes = new ArrayList<String>();
	
//	private static final String[] antlrKeywords = { "options", "grammar", "output", "ASTLabelType", "tokens", "members", "grammarDef", 
//													"tokensSpec", "tokenSpec", "attrScope", "action", "actionScopeName", "optionsSpec", "option", "optionValue",
//													"rule", "scope", "ruleAction", "throwsSpec", "ruleScopeSpec", "block", "altList", "init", "alternative", 
//													"exceptionGroup", "exceptionHandler", "finallyClause", "element", "elementNoOptionSpec", "atom", "treeSpec",
//													"notSet", "after", "ebnf", "range", "terminal", "notTerminal", "ebnfSuffix", "rewrite", "rewrite_alternative",
//													"options", "rewrite_tree_block", "rewrite_tree_alternative", "rewrite_tree_element", "rewrite_tree_atom",
//													"rewrite_tree_ebnf", "rewrite_template", "rewrite_template_ref", "rewrite_indirect_template_head", 
//													"rewrite_template_args","rewrite_template_arg", "id"};
//	private static final Set<String> antlrKeywordSet = new HashSet<String>(Arrays.asList(antlrKeywords));
	
	private final String fileName;
	private final CountDownLatch countDownLatch;
	private ParsingResult parsingResult;

	public CustomParser(String fileName, CountDownLatch countDownLatch) {
		this.fileName = fileName;
		parsingResult = new ANTLRParsingResult();
		this.countDownLatch = countDownLatch;

	}

	@Override
	public ParsingResult call() {

		try {
			ANTLRFileStream input = new ANTLRFileStream(fileName);
			ANTLRv3Lexer lexer = new ANTLRv3Lexer(input);
			CommonTokenStream tokens = new CommonTokenStream(lexer);
			ANTLRv3Parser g = new ANTLRv3Parser(tokens);
			ANTLRv3Parser.grammarDef_return r = g.grammarDef();
	        CommonTree t = (CommonTree)r.getTree();
			parseTree(t, 1);

			for (Tree variableTree : variableDeclartorNodes) {
				Tree variable = variableTree.getChild(0);
				variableList.add(variable.toString());
				// printTree(variableTree, 1);
			}
			parsingResult.setKeywordList(keywordList);
			parsingResult.setVariableList(variableList);
			parsingResult.setStringNodes(stringNodes);
			parsingResult.setStrcharNodes(strcharNodes);
			return parsingResult;
		} catch (Exception e) {
			System.out.println("Exception in parsing file" + e);
			return null;
		}finally{
			countDownLatch.countDown();
		}

	}

	public void parseTree(Tree t, int indent) {
		System.out.println(t.toString());
		parseTreeHelper(t, indent);
	}

	private void parseTreeHelper(Tree t, int indent) {

		if (t != null) {
            StringBuffer sb = new StringBuffer(indent);
            for (int i = 0; i < indent; i++)
                sb = sb.append("   ");
            for (int i = 0; i < t.getChildCount(); i++) {
            	int type = t.getChild(i).getType();
            	if(type == 29){
            		Tree variables = t.getChild(i);
            		while(variables.getChildCount() >0)
            			variables = variables.getChild(0);
            		variableList.add(variables.toString());
            	}
            	if(type == 54 || type == 15){ //Strings & characters
            		Tree strchar = t.getChild(i);
            		while(strchar.getChildCount() >0)
            			strchar = strchar.getChild(0);
            		//System.out.println("Type Child: "+ typeNode.toString());
            		strcharNodes.add(strchar.toString());
            	}
            	
            	if(type == 54){ //Strings only
            		Tree stringNode = t.getChild(i);
            		while(stringNode.getChildCount() >0)
            			stringNode = stringNode.getChild(0);
            		//System.out.println("Type Child: "+ typeNode.toString());
            		String addMe = stringNode.toString();
            		Pattern p = Pattern.compile("'[a-zA-Z0-9]+'");
            		Matcher m = p.matcher(addMe);
            		
            		if(m.matches())
            		stringNodes.add(addMe);
            	}
            	
//            	if(type == 19){
//            		Tree commentNode = t.getChild(i);
//            		while(commentNode.getChildCount() >0)
//            			commentNode = commentNode.getChild(0);
//            		//System.out.println("Type Child: "+ typeNode.toString());
//            		commentNodes.add(commentNode.toString());
//            	}

            	if(type == 59){
            		Tree keywordNode = t.getChild(i);
            		while(keywordNode.getChildCount() >0)
            			keywordNode = keywordNode.getChild(0);
            		//System.out.println("Type Child: "+ typeNode.toString());
            		keywordList.add(keywordNode.toString());
            	}
            	
                //if (t.getChild(i).getType()==4)
//                System.out.println(sb.toString() + t.getChild(i).toString()
//                + " [" + ANTLRv3Parser.tokenNames[type]
//                + "]");
                parseTreeHelper((CommonTree) t.getChild(i), indent + 1);
            }
        }
	}

}
